#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Mikan Core

Mikan Python Web Framework
"""

__author__ = "K.Sonohara"
__status__ = "develop"
__version__ = "0.0.0_46"
__date__    = "2014/05/18"
__license__ = 'LGPL'

# ------------------------------------------------------------
## Import Section
# ------------------------------------------------------------
# Python
import logging
from operator import attrgetter
from abc import ABCMeta

# ESiPC
from esipc import ESiPCProperty
from esipc import AbstractESiPC

# Mikan

# ------------------------------------------------------------
## Variable Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Mikan Contant
class MIKAN(object):
	MIKAN_NAME = "Mikan Python Web Framework"
	MIKAN_VERSION = __version__
	MIKAN_LICENSE = __license__
	MIKAN_DATE = __date__
	MIKAN_COPYRIGHT = "Copyright (C) 2012-14 K.Sonohara"

# ------------------------------------------------------------
## Mikan Ini File Contant
class MIKAN_INI(MIKAN):

	LOG_MIKAN = "mikan"
	LOG_ACCESS = "access"

	MIKAN = "mikan"
	SITE = "site"
	REALM = "realm"


	WSGI_PATH = "wsgi_path"
	WSGI_URL = "wsgi_url"
	HTDOCS_URL = "htdocs_url"
	HTDOCS_DIR = "htdocs_dir"
	APPS = "apps"

	COMPATIBLE = "compatible"
	VIEWPORT = "viewport"
	LOGO = "logo"
	TITLE = "title"
	URL = "url"
	HOSTNAME = "hostname"
	DESCRIPTION = "description"
	CONFIDENTIAL = "confidential"
	AUTHER = "auther"
	COPYRIGHT = "copyright"
	SYSTEM = "system"
	VERSION = "version"
	DATE = "date"
	PASSPHRASE = "passphrase"
	RSAPRVITEKEY = "rsaprvitekey"

# ------------------------------------------------------------
## Mikan Http Header Contant
class MIKAN_HTTP_HEADER(MIKAN):

	NAME_WWW_AUTHENTICATE = "WWW-Authenticate"
	DEFAULT_WWW_AUTHENTICATE = "Basic Authenticate"
	VALUE_WWW_AUTHENTICATE = "Basic realm=\"%s\""

	NAME_HTTP_AUTHORIZATION = "HTTP_AUTHORIZATION"
	NAME_CONTENT_ENCODING = "Content-Encoding"
	VALUE_CONTENT_ENCODING = "gzip"
	NAME_VARY = "Vary"
	VALUE_VARY = "Accept-Encoding"

	NAME_CONTENT_TYPE = "Content-Type"
	NAME_CONTENT_LENGTH = "Content-Length"
	NAME_CONTENT_DISPOSITION = "Content-Disposition"
	VALUE_CONTENT_DISPOSITION = "filename=\"%s\""

	NAME_HTTP_ACCEPT_LANGUAGE = "HTTP_ACCEPT_LANGUAGE"
	NAME_HTTP_ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING"

	NAME_REMOTE_PORT = "REMOTE_PORT"
	NAME_REMOTE_ADDR = "REMOTE_ADDR"
	NAME_REMOTE_HOST = "REMOTE_HOST"
	NAME_REMOTE_USER = "REMOTE_USER"
	NAME_HTTP_REFERER = "HTTP_REFERER"

	NAME_REQUEST_METHOD = "REQUEST_METHOD"
	VALUE_REQUEST_METHOD_HEAD = "HEAD"
	VALUE_REQUEST_METHOD_GET = "GET"
	VALUE_REQUEST_METHOD_POST = "POST"

	NAME_AUTH_TYPE = "AUTH_TYPE"

	NAME_LOCATION = "Location"
	VALUE_LOCATION = "%s"

	NAME_SCRIPT_NAME = "SCRIPT_NAME"
	NAME_PATH_INFO = "PATH_INFO"

	NAME_HTTP_COOKIE = "HTTP_COOKIE"
	NAME_HTTP_ACCEPT = "HTTP_ACCEPT"
	NAME_HTTP_ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING"
	NAME_HTTP_ACCEPT_LANGUAGE = "HTTP_ACCEPT_LANGUAGE"
	NAME_HTTP_CONNECTION = "HTTP_CONNECTION"
	NAME_HTTP_HOST = "HTTP_HOST"
	NAME_HTTPS = "HTTPS"

	NAME_HTTP_USER_AGENT = "HTTP_USER_AGENT"

	NAME_QUERY_STRING = "QUERY_STRING"

	NAME_EXPIRES = "Expires"
	VALUE_EXPIRES_NONE = "Thu, 01 Dec 1995 00:00:00 GMT"
	NAME_PRAGMA = "Pragma"
	VALUE_PRAGMA = "no-cache"
	NAME_CACHE_CONTROL = "Cache-Control"
	VALUE_CACHE_CONTROL = "no-cache"


	NAME_SET_COOKIE = "Set-Cookie"
	VALUE_TIMEOUT_SET_COOKIE = "sessionid=_; expires=Fri, 31-Dec-1999 23:59:59 GMT"

	NAME_SERVER_NAME = "SERVER_NAME"
	NAME_SERVER_PORT = "SERVER_PORT"
	NAME_SERVER_PROTOCOL = "SERVER_PROTOCOL"
	NAME_SERVER_SOFTWARE = "SERVER_SOFTWARE"
	NAME_GATEWAY_INTERFACE = "GATEWAY_INTERFACE"

# ------------------------------------------------------------
## コンテンツタイプ定義値
class MIKAN_CONTENT_TYPE(MIKAN):

	TEXT_PLAIN = "text/plain"
	TEXT_XML = "text/xml"
	TEXT_HTML = "text/html"

# ------------------------------------------------------------
## HTTPステータスコード定義値
class MIKAN_HTTP_STATUS(MIKAN):

	STATUS_CONTINUE = 100
	STATUS_SWITCHING_PROTOCOLS = 101
	STATUS_OK = 200
	STATUS_CREATED = 201
	STATUS_ACCEPTED = 202
	STATUS_NON_AUTHORITATIVE_INFORMATION = 203
	STATUS_NO_CONTENT = 204
	STATUS_RESET_CONTENT = 205
	STATUS_PARTIAL_CONTENT = 206
	STATUS_MULTIPLE_CHOICES = 300
	STATUS_MOVEDPERMANENTLY = 301
	STATUS_FOUND = 302
	STATUS_SEE_OTHER = 303
	STATUS_NOT_MODIFIED = 304
	STATUS_USE_PROXY = 305
	STATUS_UNUSED = 306
	STATUS_TEMPORARY_REDIRECT = 307
	STATUS_BAD_REQUEST = 400
	STATUS_UNAUTHORIZED = 401
	STATUS_PAYMENT_REQUIRED = 402
	STATUS_FORBIDDEN = 403
	STATUS_NOT_FOUND = 404
	STATUS_METHOD_NOT_ALLOWED = 405
	STATUS_NOT_ACCEPTABLE = 406
	STATUS_PROXY_AUTHENTICATION_REQUIRED = 407
	STATUS_REQUEST_TIMEOUT = 408
	STATUS_CONFLICT = 409
	STATUS_GONE = 410
	STATUS_LENGTH_REQUIRED = 411
	STATUS_PRECONDITION_FAILED = 412
	STATUS_REQUEST_ENTITY_TOO_LARGE = 413
	STATUS_REQUEST_URI_TOO_LONG = 414
	STATUS_UNSUPPORTED_MEDIA_TYPE = 415
	STATUS_REQUESTED_RANGE_NOT_SATISFIABLE = 416
	STATUS_EXPECTATION_FAILED = 417
	STATUS_INTERNAL_SERVER_ERROR = 500
	STATUS_NOT_IMPLEMENTED = 501
	STATUS_BAD_GATEWAY = 502
	STATUS_SERVICE_UNAVAILABLE = 503
	STATUS_GATEWAY_TIMEOUT = 504
	STATUS_HTTP_VERSION_NOT_SUPPORTED = 505

	CODES = {
		100:'Continue',
		101:'Switching Protocols',
		200:'OK',
		201:'Created',
		202:'Accepted',
		203:'Non-Authoritative Information',
		204:'No Content',
		205:'Reset Content',
		206:'Partial Content',
		300:'Multiple Choices',
		301:'MovedPermanently',
		302:'Found',
		303:'See Other',
		304:'Not Modified',
		305:'Use Proxy',
		306:'Unused',
		307:'Temporary Redirect',
		400:'Bad Request',
		401:'Unauthorized',
		402:'Payment Required',
		403:'Forbidden',
		404:'Not Found',
		405:'Method Not Allowed',
		406:'Not Acceptable',
		407:'Proxy Authentication Required',
		408:'Request Timeout',
		409:'Conflict',
		410:'Gone',
		411:'Length Required',
		412:'Precondition Failed',
		413:'Request Entity Too Large',
		414:'Request-Uri Too Long',
		415:'Unsupported Media Type',
		416:'Requested Range Not Satisfiable',
		417:'Expectation Failed',
		500:'Internal Server Error',
		501:'Not Implemented',
		502:'Bad Gateway',
		503:'Service Unavailable',
		504:'Gateway Timeout',
		505:'Http Version Not Supported',
	}

# ------------------------------------------------------------
## Function Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Class Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Mikan 抽象 クラス
class AbstractMikan(AbstractESiPC, MIKAN):
	__metaclass__ = ABCMeta

	# ----------------------------------------------------
	## コンストラクタ
	def __init__(self):
		# 値の設定
		self.flogger = None

		# ログ
		if self.islogdebug:
			self.logger.debug(self.__class__)

	# ----------------------------------------------------
	## ロガー フィールドゲッター
	# @return 取得した値
	def get_logger(self):
		# 未初期化の場合
		if (AbstractMikan.flogger == None):
			return logging.getLogger(MIKAN_INI.LOG_MIKAN)
		# 処理結果
		return AbstractMikan.flogger

	def get_mikan_root(self):
		try:
			return AbstractMikan.fmikanroot
		except:
			return None

	def get_mikan_config(self):
		try:
			return AbstractMikan.fmikanconfig
		except:
			return None

	# ----------------------------------------------------
	## Property
	mikanroot = ESiPCProperty(get_mikan_root, None, None)
	mikanconfig = ESiPCProperty(get_mikan_config, None, None)

# ------------------------------------------------------------
## Mikan 抽象処理 クラス
class AbstractMikanPerform(AbstractMikan):
	__metaclass__ = ABCMeta

	def set_on_prepare(self, value):
		self.FOnPrepare = value

	def get_on_prepare(self):
		return self.FOnPrepare

	def set_on_perform(self, value):
		self.FOnPerform = value

	def get_on_perform(self):
		return self.FOnPerform

	# ----------------------------------------------------
	## コンストラクタ
	#  @param request リクエスト
	def __init__(self, request):
		# 継承元実行
		super(AbstractMikanPerform, self).__init__()

		# 値の設定
		self.FRequest = request
		self.FPerforms = []
		self.FSortKey = 0

		self.FOnPrepare = None
		self.FOnPerform = None

	def set_sortkey(self,value):
		self.FSortKey = value

	def get_sortkey(self):
		return self.FSortKey

	def get_performs(self):
		return self.FPerforms

	def get_request(self):
		return self.FRequest

	def get_webapp(self):
		return self.request.webapp

	def get_site_session(self):
		return self.webapp.sitesession

	# ----------------------------------------------------
	## 事前処理
	# @return Trueなら続行
	def prepare(self):
		# ログ
		if self.islogdebug:
			self.logger.debug(self)

		if self.onprepare:
			if not self.onprepare(self):
				return False

		# 実行前 ソート
		self.FPerforms = sorted(self.performs, key=attrgetter('sortkey'))

		# 処理結果
		return True

	# ----------------------------------------------------
	## 処理
	# @return Trueなら続行
	def perform(self):
		if self.onperform:
			if not self.onperform(self):
				return False

		# 子処理
		for p in self.performs:
			# ログ
			if self.islogdebug:
				self.logger.debug(p.__class__)
				self.logger.debug("sort: %d", int(p.sortkey))

			# 子の事前処理
			if p.prepare():
				# ログ
				if self.islogdebug:
					self.logger.debug(True)

				# 子の処理
				if not p.perform():
					# ログ
					if self.islogdebug:
						self.logger.debug(False)
					return False

		# ログ
		if self.islogdebug:
			self.logger.debug(self)

		# 処理結果
		return True

	# ----------------------------------------------------
	## Property
	onprepare = ESiPCProperty(get_on_prepare, set_on_prepare, None)
	onperform = ESiPCProperty(get_on_perform, set_on_perform, None)
	request = ESiPCProperty(get_request, None, None)
	webapp = ESiPCProperty(get_webapp, None, None)
	sitesession = ESiPCProperty(get_site_session, None, None)
	performs = ESiPCProperty(get_performs, None, None)
	sortkey = ESiPCProperty(get_sortkey, set_sortkey, None)

# ------------------------------------------------------------
## Main Section
# ------------------------------------------------------------

# ------------------------------------------------------------
